package com.ydl.iec.iec104.controller;

import com.ydl.iec.iec104.common.TdenginData;
import com.alibaba.fastjson.JSONArray;
import com.ydl.iec.iec104.common.CommonUtils;
import com.ydl.iec.iec104.common.TdenginData;
import com.ydl.iec.iec104.common.TelemeteringData;
import com.ydl.iec.iec104.config.Iec104Config;
import com.ydl.iec.iec104.handler.MasterSysDataHandler;
import com.ydl.iec.iec104.handler.SysDataHandler;
import com.ydl.iec.iec104.server.Iec104MasterFactory;
import com.ydl.iec.iec104.server.Iec104SlaveFactory;
import com.ydl.iec.iec104.server.handler.Check104Handler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;

import static com.ydl.iec.iec104.common.Telecontrol.*;
import static java.util.concurrent.Executors.*;

/**
 *
 * @ClassName: Iec104ServerInitializer
 * @Description: 104协议 启动
 * @author YDL
 * @date 2020年5月13日
 */
@RestController
@EnableScheduling
public class Iec104Controller {
    private static final Logger LOGGER = LoggerFactory.getLogger(Iec104Controller.class);

    @Autowired(required = false)
    private AmqpTemplate rabbitTemplate;

    @Value ("${stid.dg}")
    private String dg;

    @Value ("${stid.fj}")
    private String fj;

	@Value ("${stid.kt}")
	private String kt;

    public static byte[] YZ = {1};

    //判断是否需要控制开关
    public static String TYPE = "1";

    //是否收到测试指令
    public static String CSZL = "未收到测试确认";


    @RequestMapping(value = "/masterStart", method = RequestMethod.GET)
    public void master(String ip , Integer port) throws Exception {
        LOGGER.info ("建立连接，创建主站时间："+  new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss").format (new Date ()));
        Iec104Config iec104Config  = new Iec104Config();
        iec104Config.setFrameAmountMax((short) 2);
        iec104Config.setTerminnalAddress((short) 1);
        Iec104MasterFactory.createTcpClientMaster(ip, port).setDataHandler(new MasterSysDataHandler()).setConfig(iec104Config).run();
        Thread.sleep(1000000);
    }

    @RequestMapping(value = "/slaveStart", method = RequestMethod.GET)
    public void slave(int port) throws Exception {
        Iec104Config iec104Config  = new Iec104Config();
        iec104Config.setFrameAmountMax((short) 1);
        iec104Config.setTerminnalAddress((short) 1);
        Iec104SlaveFactory.createTcpServerSlave(port).setDataHandler(new SysDataHandler()).setConfig(iec104Config).run();
    }

    /**
     * 遥控
     * @param state
     * @param entity_id
     */
    @RequestMapping("/sendYkzl")
    public List<Map<String,Object>> sendZl(String entity_id, String state) {
        //判断条件使用哪一个指令，控制哪个开关
        if (dg.equals (entity_id) && "off".equals (state)){
            YZ = YZDG_CLOSE;
        }else if (dg.equals (entity_id) && "on".equals (state)){
            YZ = YZDG_OPEN;
        }else if (fj.equals (entity_id) && "off".equals (state)){
            YZ = YZFJ_CLOSE;
        }else if (fj.equals (entity_id) && "on".equals (state)){
            YZ = YZFJ_OPEN;
        }else if (kt.equals (entity_id) && "off".equals (state)){
			YZ = YZKT_CLOSE;
		}else if (kt.equals (entity_id) && "on".equals (state)){
			YZ = YZKT_OPEN;
		}

        ArrayList<Map<String, Object>> list = new ArrayList<> ();
        HashMap<String, Object> map = new HashMap<> (2);
        map.put ("entity_id",entity_id);
        map.put ("state",state);

        //判断是否执行遥控的条件，默认为1，修改为2时会进行遥控
        TYPE = "2";

        list.add (map);
        return list;
    }


    public static ExecutorService executorService = newFixedThreadPool(20);

    /**
     * 判断是否收到测试确认指令
     */
    @RequestMapping("/masterCron")
    private String csZlQr(@RequestBody List<HashMap<String,Object>> list) throws Exception {
        LOGGER.info ("目前CSZL状: " + CSZL);
        if ("未收到测试确认".equals (CSZL)) {
            for (int i = 0; i < list.size (); i++) {
                HashMap<String, Object> map = list.get (i);
                executorService.execute(() -> {
                    try {
                        master(map.get ("ip").toString (),Integer.parseInt (map.get ("port").toString ()));
                    } catch (Exception e) {
                        e.printStackTrace ();
                    }
                });
            }
            return "重新建立连接 ==>>>成功";
        }else {
            CSZL = "未收到测试确认";
            return "目前无需重新建立连接";
        }

    }

    @RequestMapping(value = "/mqPush", method = RequestMethod.GET)
    public Object mqPush() {
        System.out.println ("Check104Handler.resultList:" + Check104Handler.resultList);
        LOGGER.info ("mq推送时间"+new Date ());
        if (StringUtils.isEmpty(Check104Handler.resultList)){
            return "Check104Handler.resultList为空";
        }
        if (Check104Handler.resultList.size ()>0) {
			//推送mysql入库数据
	        rabbitTemplate.convertAndSend("zaozhJy", Check104Handler.resultList);
	        LOGGER.info("mq推送遥测数据为：" + Check104Handler.resultList);
	        ArrayList<TdenginData> tdenginList = new ArrayList<>();
			//推送时序数据库入库数据
	        ArrayList<Object> list = Check104Handler.list;
	        if (list.size() == 39) {
		        tdenginList.add(new TdenginData("温湿度1", list.get(0).toString()
				        , list.get(1).toString(), list.get(2).toString(),
				        list.get(3).toString(), list.get(4).toString()));
		        tdenginList.add(new TdenginData("温湿度2", list.get(5).toString()
				        , list.get(6).toString(), list.get(7).toString(),
				        list.get(8).toString(), list.get(9).toString()));
		        tdenginList.add(new TdenginData("水浸1", list.get(10).toString()
				        , list.get(11).toString(), list.get(12).toString(), null, null));
		        tdenginList.add(new TdenginData("水浸2", list.get(13).toString()
				        , list.get(14).toString(), list.get(15).toString(), null, null));
		        tdenginList.add(new TdenginData("六氟化硫1", list.get(16).toString()
				        , list.get(17).toString(), null, null, null));
		        tdenginList.add(new TdenginData("六氟化硫2", list.get(18).toString()
				        , list.get(19).toString(), null, null, null));
		        tdenginList.add(new TdenginData("烟感1", list.get(20).toString()
				        , list.get(21).toString(), list.get(22).toString(), null, null));
		        tdenginList.add(new TdenginData("烟感2", list.get(23).toString()
				        , list.get(24).toString(), list.get(25).toString(), null, null));
		        tdenginList.add(new TdenginData("风机", list.get(26).toString()
				        , null, null, null, null));
		        tdenginList.add(new TdenginData("灯光", list.get(27).toString()
				        , null, null, null, null));
		        tdenginList.add(new TdenginData("空调", list.get(28).toString()
				        , list.get(29).toString(), list.get(30).toString(), list.get(31).toString(),
				        list.get(32).toString(),list.get(33).toString(),list.get(34).toString(),list.get(35).toString()));
		        tdenginList.add(new TdenginData("局放", list.get(36).toString()
				        , list.get(37).toString(), list.get(38).toString(), null, null));
	        }
	        rabbitTemplate.convertAndSend("zaozhTdengin", tdenginList);
        }
	    return "Check104Handler.resultList:" + Check104Handler.resultList;
    }

//	@RequestMapping("/test")
	public void tset() {
		ArrayList<Object> list = new ArrayList<>();
		String analysis = "*APCI应用规约控制信息*\n" +
				"启动字符[1 byte]: 0x68 \n" +
				"应用规约数据单元(APDU)长度[2 byte]:153字节\n" +
				"控制域[3 byte - 6 byte]：\n" +
				"\t(I格式控制域标志)\n" +
				"\t发送序列号：4\n" +
				"\t接受序列号：2\n" +
				"*ASDU应用服务数据单元*\n" +
				"类属性标识符[7 byte]:测量值，短浮点数\n" +
				"可变结构限定词[8 byte]:可变结构限定词:0x9C   SQ=1 信息元素地址顺序     信息元素个数：28\n" +
				"传送原因[9 byte - 10 byte]:[T(test) bit7:0  未实验][P/N  bit6:0  肯定确认][原因  bit5~bit0:响应站召唤（总召唤）]\n" +
				"应用服务数据单元公共地址[11 byte - 12 byte]：0001H\n" +
				"遥测信息对象地址16385(004001H)\n" +
				"遥测1IEEE STD745短浮点数:27.024351\n" +
				"品质描述词QDS:0x00\n" +
				"遥测2IEEE STD745短浮点数:44.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测3IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测4IEEE STD745短浮点数:-99999.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测5IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测6IEEE STD745短浮点数:26.970726\n" +
				"品质描述词QDS:0x00\n" +
				"遥测7IEEE STD745短浮点数:46.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测8IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测9IEEE STD745短浮点数:-99999.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测10IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测11IEEE STD745短浮点数:-99999.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测12IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测13IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测14IEEE STD745短浮点数:-99999.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测15IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测16IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测17IEEE STD745短浮点数:20.9\n" +
				"品质描述词QDS:0x00\n" +
				"遥测18IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测19IEEE STD745短浮点数:20.9\n" +
				"品质描述词QDS:0x00\n" +
				"遥测20IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测21IEEE STD745短浮点数:-99999.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测22IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测23IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测24IEEE STD745短浮点数:-99999.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测25IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测26IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测27IEEE STD745短浮点数:1.0\n" +
				"品质描述词QDS:0x00\n" +
				"遥测28IEEE STD745短浮点数:0.0\n" +
				"品质描述词QDS:0x00";

		if (analysis.contains("遥测")) {
			String data = analysis.split("遥测1IEEE STD745短浮点数:")[1];
			String[] split = data.split("短浮点数:");
			for (String s : split) {
				String s1 = s.split("\n遥测")[0];
				if (s1.contains("\n")) {
					list.add(s1.split("\n")[0]);
				} else {
					list.add(s1);
				}
			}
		}
		ArrayList<TelemeteringData> resultList = new ArrayList<>();
		if (list.size() == 28) {
			for (int i = 1; i < list.size() + 1; i++) {
				resultList.add(new TelemeteringData(CommonUtils.getSbms(i), CommonUtils.getdms(i), i, CommonUtils.getdh(i), list.get(i - 1).toString(), i < 10 ? "100002400" + i : "10000240" + i));
			}
		}

		rabbitTemplate.convertAndSend("zaozhJy", resultList);
		System.out.println(list);
		System.out.println(resultList);

		ArrayList<TdenginData> tdenginList = new ArrayList<>();
		tdenginList.add(new TdenginData("温湿度1", list.get(0).toString()
				, list.get(1).toString(), list.get(2).toString(),
				list.get(3).toString(), list.get(4).toString()));
		tdenginList.add(new TdenginData("温湿度2", list.get(5).toString()
				, list.get(6).toString(), list.get(7).toString(),
				list.get(8).toString(), list.get(9).toString()));
		tdenginList.add(new TdenginData("水浸1", list.get(10).toString()
				, list.get(11).toString(), list.get(12).toString(), null, null));
		tdenginList.add(new TdenginData("水浸2", list.get(13).toString()
				, list.get(14).toString(), list.get(15).toString(), null, null));
		tdenginList.add(new TdenginData("六氟化硫1", list.get(16).toString()
				, list.get(17).toString(), null, null, null));
		tdenginList.add(new TdenginData("六氟化硫2", list.get(18).toString()
				, list.get(19).toString(), null, null, null));
		tdenginList.add(new TdenginData("烟感1", list.get(20).toString()
				, list.get(21).toString(), list.get(22).toString(), null, null));
		tdenginList.add(new TdenginData("烟感2", list.get(23).toString()
				, list.get(24).toString(), list.get(25).toString(), null, null));
		tdenginList.add(new TdenginData("风机", list.get(26).toString()
				, null, null, null, null));
		tdenginList.add(new TdenginData("灯光", list.get(27).toString()
				, null, null, null, null));
		String s = JSONArray.toJSONString(tdenginList);
		System.out.println("zaozhTdengin:" + tdenginList);
		System.out.println("s:" + s);
		rabbitTemplate.convertAndSend("zaozhTdengin", tdenginList);
	}
}
